﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
using XLua;
using Yoozoo.Framework.Core;
using Yoozoo.Manager;
using Yoozoo.Utils;

namespace com.yoozoo.gta.Extension
{
    public class TextTranslator : SingletonMono<TextTranslator>
    {
        private string appID = "8sAxaw7QUTqXsT9";
        private string appKey = "x3BktIIWrtSFwjLMK1Zb";
        private string debugAddress = "https://qatranslator-api.gtarcade.com/translator";
        private string releaseAddress = "https://translator-api.gtarcade.com/translator";

        private StringBuilder sb = new StringBuilder(512);
        private Dictionary<string, TranslateTask> tasks = new Dictionary<string, TranslateTask>();
        private List<string> waitRemoveTasks = new List<string>();
        
        // callback lua function(string, string)
        public void PublicTranslateTask(string text, int time, string targetLanguageCode, LuaFunction callback,
            float timeout = 10)
        {
            text = text.Trim();
            if (string.IsNullOrEmpty(text))
            {
                callback?.Action(text, string.Empty);
                EventTracingManager.GetInstance().ClientReportError("TextTranslator Args Error (text is empty)");
                return;
            }

            TranslateTask task;
            if (this.tasks.TryGetValue(text, out task))
            {
                task.callbacks.Add(callback);
                return;
            }

            this.sb.Clear();
            this.sb.Append("client_id=");
            this.sb.Append(this.appID);
            
            this.sb.Append("&text=");
            this.sb.Append(text);
            
            this.sb.Append("&time=");
            this.sb.Append(time);
            
            this.sb.Append("&to=");
            this.sb.Append(targetLanguageCode);

            this.sb.Append(this.appKey);


            task = new TranslateTask
            {
                startTime = Time.time,
                timeount = timeout,
                callbacks = new List<LuaFunction>()
            };
            
            task.callbacks.Add(callback);
            this.tasks.Add(text, task);

            var md5 = GStringUtils.Parse2MD5(this.sb.ToString());
            
            var args = new WWWForm();
            args.AddField("text", text);
            args.AddField("to", targetLanguageCode);
            args.AddField("client_id", this.appID);
            args.AddField("time", time);
            args.AddField("verify", md5);
            
            var argsStr = string.Format("text={0}&to={1}&client_id={2}&time={3}&verify={4}", text, targetLanguageCode, this.appID, time, md5);
            StartCoroutine(SendWebRequest(text, args, argsStr));
        }
        
        private IEnumerator SendWebRequest(string text, WWWForm args, string argstr)
        {
            using (UnityWebRequest uwr = UnityWebRequest.Post(this.releaseAddress, args))
            {
                uwr.downloadHandler = new DownloadHandlerBuffer();
                yield return uwr.SendWebRequest();
                
                if (uwr.isNetworkError || uwr.isHttpError)
                {
                    //上报一下错误
                    UploadTranslateError("TextTranslator Network Error", uwr);
                    OnTranslateRsp(text);
                }
                else
                {
                    var newText = uwr.downloadHandler.text.Replace(" ", "\\u00A0");
                    var result = JsonConvert.DeserializeObject<TranslateResult>(newText);
                    if (String.IsNullOrEmpty(result.data))
                    {
                        var errArgs = string.Format("original={0},result={1},reqArgs={2}", text, newText, argstr);
                        UploadTranslateError("TextTranslator data Error", uwr, errArgs);
                    }
                    OnTranslateRsp(text, result.data);
                }
            }
        }
        
        private void UploadTranslateError(string desc, UnityWebRequest uwr, string args = "")
        {
            if (String.IsNullOrEmpty(args))
            {
                var headers = uwr.GetResponseHeaders();
                args = "";
                foreach (var kvp in headers)
                {
                    args += kvp.Key + ":" + kvp.Value + ",";
                }
            }
            var error = uwr.error ?? "null";
            Debug.LogError(string.Format("TextTranslator Error: desc={0}, code={1}, msg={2}, args={3}", 
                desc, uwr.responseCode, error, args));
            
            Dictionary<string, string> log = new Dictionary<string, string>();
            log["log_type"] = "客户端错误上报日志";
            log["extra_3"] = desc;
            log["extra_4"] = "" + uwr.responseCode;
            log["extra_5"] = "" + error;
            log["extra_6"] = args;
            string json = LitJson.JsonMapper.ToJson(log);
            EventTracingManager.GetInstance().ClientRoleExtra(json);
        }

        private void OnTranslateRsp(string text, string translated = "")
        {
            TranslateTask task;
            if (!this.tasks.TryGetValue(text, out task))
            {
                return;
            }

            foreach (var callback in task.callbacks)
            {
                callback?.Action(text, translated);   
            }

            this.tasks.Remove(text);
        }

        private void Update()
        {
            var t = Time.time;
            foreach (var kvp in this.tasks)
            {
                var task = kvp.Value;
                if (t - task.startTime >= task.timeount)
                {
                    foreach (var callback in task.callbacks)
                    {
                        callback?.Action(kvp.Key, "");   
                    }

                    this.waitRemoveTasks.Add(kvp.Key);
                }
            }

            foreach (var key in this.waitRemoveTasks)
            {
                this.tasks.Remove(key);
            }
            
            this.waitRemoveTasks.Clear();
        }
    }
    
    class TranslateResult
    {
        public int classify;
        public string client_id;
        public string data;
        public string desc;
        public int status;
        public string from;
        public string to;
    }

    class TranslateTask
    {
        public float startTime;
        public float timeount;
        public List<LuaFunction> callbacks;
    }
}